#include "util.h"

bool Request::stressIsRunning=true;
vector<data_t> Request::vecData;
string Request::strFileName="/home/xiamc/prophet_head.txt";
string Request::strLogName="./log.txt";
string Request::strIp;
string Request::strPage="/";
unsigned long Request::ratio=32;
unsigned long Request::stressInterval=1;
unsigned long Request::stressCount=0;
unsigned long Request::stressThreadnum=8;
std::ofstream Request::stresslog;
int  Request::intPort=80;
FILE *Request::fin=NULL;
pthread_mutex_t Request::_intReponseTimeMtx=PTHREAD_MUTEX_INITIALIZER;
std::map<int,int> Request::_responseTimeMap;
unsigned int Request::_intMaxResponseTime=0;
unsigned int Request::_intMinResponseTime=65533000;
unsigned int Request::_totalResponseTime =0;
ret_t Request::ret;
struct timeval Request::start,Request::end;

void Request::addIntResponseTime(struct timeval &startTime,
            struct timeval &endTime) {
    pthread_mutex_lock(&_intReponseTimeMtx);
    int timeVal = (endTime.tv_sec - startTime.tv_sec) * 10000 +
        (endTime.tv_usec - startTime.tv_usec) / 100;    
    if (timeVal < 0) {
        timeVal = 0;
    }
    map<int,int>::const_iterator it=Request::_responseTimeMap.find(timeVal);
    if(it==Request::_responseTimeMap.end())
        Request:: _responseTimeMap.insert(make_pair(timeVal,1));
    else
        Request::_responseTimeMap[timeVal]++;
    if(timeVal > _intMaxResponseTime){
        _intMaxResponseTime = timeVal;
    }
    if(timeVal < _intMinResponseTime){
        _intMinResponseTime = timeVal;
    }
    _totalResponseTime += timeVal;
    pthread_mutex_unlock(&_intReponseTimeMtx);
}



void Request::openFile()
{
    if((Request::fin=fopen(Request::strFileName.c_str(),"r"))==NULL)
    {
        string error="open input file error!"+Request::strFileName;
        perror(error.c_str());
        exit(1);
    }
}



int read_data(int sock_fd,char *buffer, int buffer_len,string &errorInfo)
{
    char *ptemp = buffer;
    int bytes_to_recv = buffer_len;
    int bytes_recv = 0;
    if (sock_fd < 0 || NULL == buffer || buffer_len <= 0)
    {
        return -1;
    }
    while (bytes_to_recv > 0)
    {
        //bytes_recv = read(sock_fd, ptemp, bytes_to_recv);
        bytes_recv = recv(sock_fd, ptemp, bytes_to_recv, 0);
        if (0 == bytes_recv)
        {
            // the server has close the connection gracefully.
            fprintf(stdout,"close fd, no data to read");
            close(sock_fd);
            return -1;
        }
        else if (bytes_recv < 0)
        {
            if ((EINTR == errno) || (EAGAIN == errno))
            {
                continue;
            }
            else
            {
                errorInfo="close fd,  data less than 0";
                close(sock_fd);
                return -1;
            }
        }
        else
        {
            ptemp += bytes_recv;
            bytes_to_recv -= bytes_recv;
        }
    }
    return 0;
}

int write_data(int sock_fd,const char *buffer, int buffer_len,string &errorInfo)
{
    const char *ptemp = buffer;
    int bytes_to_recv = buffer_len;
    int bytes_recv = 0;
    if (sock_fd < 0 || NULL == buffer || buffer_len <= 0)
    {
        return -1;
    }
    while (bytes_to_recv > 0)
    {
        //cout<<endl<<"bytes_to_recv:\t"<<bytes_to_recv<<"bytes_recv\t"<<bytes_recv<<endl;
        bytes_recv = write(sock_fd, ptemp, bytes_to_recv);
        if (0 == bytes_recv)
        {
            // the server has close the connection gracefully.
            errorInfo="close fd, no data to write,length:\n";
            close(sock_fd);
            return -1;
        }
        else if (bytes_recv < 0)
        {
            if ((EINTR == errno) || (EAGAIN == errno) || (EWOULDBLOCK == errno))
            {
                continue;
            }
            else
            {
                errorInfo="close fd, write data: less than 0,bytes_to_recv:\n";
                close(sock_fd);
                return -1;
            }
            //continue;
        }
        else
        {
            ptemp += bytes_recv;
            bytes_to_recv -= bytes_recv;
        }
    }
    return 0;
}

int Request::getStatus(char *response)
{
    int ret=0;
    bool negative;
//HTTP/1.1 200 OK
    char *p=response;
    while(*p==' ') p++;
    while(*p!=' ') p++;
    p++;
    if(*p=='-')
    {
        negative=true;
        p++;
    }
    while(*p!=' ')
    {
        ret=10*ret+(*p-'0');
        p++;
    }
    if(negative==true) ret=0-ret;
    //cout<<"ret:\t"<<ret<<endl;
    return ret;
}

int Request::doPost(int sockfd,string page,string &data,string &host,int port)
{
    
    if(sockfd<0)
        return -1;
    string str;
    //const char *header2="User-Agent: Tuobao Http 0.1\r\nCache-Control: no-cache\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept: */*\r\n";
    //sprintf(post,"POST %s HTTP/1.0\r\n",page);
    //sprintf(host,"HOST: %s:%d\r\n",pclient->remote_ip,pclient->remote_port);
    //sprintf(content_len,"Content-Length: %d\r\n\r\n",strlen(request));
    //strcpy(lpbuf,post);
    //strcat(lpbuf,host);
    //strcat(lpbuf,header2);
    //strcat(lpbuf,content_len);
    //strcat(lpbuf,request);
    //int SIZE=1024;

    char content_len[SIZE],d[SIZE],strPort[SIZE];
    snprintf(content_len,SIZE,"%ld",data.size());
    //snprintf(content_len,SIZE,"%ld",strlen(data));
    snprintf(strPort,SIZE,"%ld",port);
    //cout<<"content_len:\t"<<content_len<<endl;
    str="POST "+page+" HTTP/1.0\r\n"+ 
        "HOST: "+host+":"+strPort+"\r\n"+ 
        "User-Agent: chrome Http 0.1\r\n"+ 
        "Cache-Control: no-cache\r\n"+ 
        "Content-Type: application/x-www-form-urlencoded\r\n"+ 
        "Accept: */*\r\n"+ 
        "Connection: Keep-Alive\r\n"+ 
        "Content-Length: "+content_len+"\r\n\r\n";
    //cout<<"\ndata\t"<<data<<endl;
    //cout<<"str\t"<<str<<"\ndata_len:\t"<<data.size()<<endl;
    str=str  +  data;
    if(write_data(sockfd,str.c_str(),str.size(),errorInfo)==-1)
	{
		//perror("send error!");
	    errorInfo="send error!";
		close(sockfd);
        return -1;
        //exit(0);
	}
    //cout<<"write data finished"<<endl;
    read_data(sockfd,d,15,errorInfo);
    int retCode=getStatus(d);
    Request::stresslog << "response code:\t"<<retCode << endl;
    if(retCode==200)
        return 0;
    else
        return 1;
    
    //cout << "respose: \t "<<d <<endl;

    /*
    read(sockfd,d,SIZE);
    cout<<"receive data\r\n"<<d<<endl;
    while(read(sockfd,d,SIZE)>0)
    {
        cout<<"receive data\r\n"<<d<<endl;
    }
    */
}

int Request::doGet(int sockfd,string page,string data,string host,int port)
{
    if(sockfd<0)
        return -1;
    string str;

    char content_len[SIZE],d[SIZE],strPort[SIZE];

    snprintf(content_len,SIZE,"%ld",data.size());
    snprintf(strPort,SIZE,"%ld",port);
    //content_len[strlen(data.size())+1]='\0';
    page="/";
    str="GET "+page+" HTTP/1.0\r\n"+ 
        "HOST: "+host+":"+strPort+"\r\n"+ 
        "User-Agent: chrome Http 0.1\r\n"+ 
        "Cache-Control: no-cache\r\n"+ 
        "Content-Type: application/x-www-form-urlencoded\r\n"+ 
        "Accept: */*\r\n"+
        "Connection: Close\r\n\r\n"; 
        //"Referer: "+data+"\r\n\r\n";
    //cout<<"str\n"<<str<<endl;
    cout<<"str\t"<<str<<"\ndata_len:\t"<<str.size()<<endl;
    if(write_data(sockfd,str.c_str(),str.size(),errorInfo)==-1)
	{
		perror("send error!");
		close(sockfd);
        return -1;
		//exit(0);
	}
    read(sockfd,d,SIZE);
    cout<<"receive data\r\n"<<d<<endl;
    while(read(sockfd,d,SIZE)>0)
    {
        cout<<"receive data\r\n"<<d<<endl;
    }
}


int Request::work(unsigned int i)
{
    struct timeval starttime,endtime;
    //Request request(strFileName);
    signal(SIGPIPE,SIG_IGN);
    int sockfd,recvbytes;
    string ip="",page="/",data;
    char buffer[SIZE];
    char dns_buff[8192];
    int port=8080;

    //ip="10.20.146.85";
    //page="/esmart";
    ip=Request::strIp;
    //cout<<"ip\t"<<Request::strIp<<endl;
    page=strPage;
    port=intPort;
    struct hostent *host=NULL,hostinfo;
    int flag,rc;
    time_t now;
    uint32_t ip4;
    struct sockaddr_in serv_addr;
    memset(&serv_addr,0,sizeof(serv_addr));
    serv_addr.sin_family=AF_INET;
    serv_addr.sin_port=htons(port);
    if(ip[0]<'0'||ip[0]>'9')
    {
/*
        //if(gethostbyname_r(ip.c_str(),&hostinfo,dns_buff,8192,&host,&rc)!=0)
        if((host=gethostbyname(ip.c_str()))!=NULL)
        {
            herror("gethostbyname error!");
            //exit(1);
            return -1;
        }
        if(host)     serv_addr.sin_addr=*((struct in_addr*)host->h_addr);
        else return -1;
        //fprintf(stdout,"get hostname:%s\n",host->h_addr);
*/
    }
    else
    {
        if(inet_pton(AF_INET,ip.c_str(), &serv_addr.sin_addr) <= 0){
            printf("inet_pton error for %s\n",ip.c_str());
            return -1;
        }
        //fprintf(stdout,"get hostname:%s\n",ip.c_str());
    }
    //data="/";

    if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
    {
        //perror("socket creation error!");
        errorInfo="socket creation error!";
        return -1;
    }
    if(connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr))<0)
    {
        perror("connect error!");
        errorInfo="connect error!";
        return -2;
    }
    //fprintf(stdout,"connect to %s\n",ip.c_str());
    //cout<<"send data"<<endl;
    //data.clear();

    //fcntl(sockfd, F_SETFL, O_NONBLOCK);
    //long position=Request::vecData[i].pos;
    //long length=Request::vecData[i].length;
    //fseek(fin, position, SEEK_SET);

    //position++;
    
    /*
    //ssize_t read(int fd, void *buf, size_t count);
    //char *p=(char *)malloc(length*sizeof(char));
    //long ret=0;
    //if((ret=read(fileno(fin),p,length))!=length)
    //if((ret=read_data(fileno(fin),p,length))!=0)
    //{
    //    cout<<"read file error!"<<endl;
    //    cout<<"lineno\t"<<i<<"ret\t"<<ret<<"\tlength\t"<<length<<endl;
    //    exit(1);
    //}
    //cout<<"lineno\t"<<i<<"ret\t"<<ret<<"\tlength\t"<<length<<endl;
    //if(p[length-1]=='\n') cout<<"line over"<<endl;

    *(p+length-1)='\0';
    */
    /*
    while(fgets(buffer,SIZE,fin))
    {
        if(buffer[strlen(buffer)]=='\0'&&buffer[strlen(buffer)-1]=='\n')
        {
            buffer[strlen(buffer)-1]='\0';
            data=data+buffer;
            break;
        }
        else
        {
            data=data+buffer;
        }
    }
    */
    //cout<<"lineno\t"<<i<<"\tlength\t"<<length<<endl;
    //char *p=(char *)malloc(length*sizeof(char));
    //memcpy(p,data.c_str(),data.size());
    gettimeofday(&starttime,NULL);
    //string f=Request::vecData[i].data;
    if(doPost(sockfd,page,Request::vecData[i].data,ip,port)<0)
    //if(doGet(sockfd,page,data,ip,port)<0)
    {
        //cout<<"doPost error!"<<endl;
        return -1;
    }
    //cout<<"send index\t"<<i<<endl;
    gettimeofday(&endtime,NULL);
    Request::addIntResponseTime(starttime,endtime);
    //cout<<"post ended!"<<endl;
    //delete p;
    close(sockfd);
    return 0;
}
